package video;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;

import java.util.*;

import org.gstreamer.Bus;
import org.gstreamer.GstObject;
import org.gstreamer.Bus.EOS;

import rss.News;

/**
 * Class that manager the the video features.
 * 
 * @version 0.3 December 01, 2009.
 * @author Heitor Meira de Melo.
 */

public class Player {
	private PlayList playlist;
	private VideoPlayer player;
	private EOS endOfVideo;

	/**
	 * A player constructor
	 * 
	 * @param files
	 *            A List of video files.
	 * @param news
	 *            A News instance.
	 * @throws Exception
	 *             If file is null or empty.
	 */
	public Player(List<String> files, News news) throws Exception {
		playlist = new PlayList(files);
		endOfVideoEvent();
		player = new VideoPlayer(endOfVideo, news);
	}

	/**
	 * Creates a video, in a new thread, ready to play .
	 * 
	 * @return The video.
	 * @throws If
	 *             the file is invalid.
	 */
	public RunVideo createPlayer() throws Exception {
		RunVideo runVideo = player.createPlayer(currentVideo());
		upadateKeyListeners();
		return runVideo;
	}

	/**
	 * Stop the video and sets the components to null.
	 * 
	 */
	public void kill() {
		player.kill();
	}

	/**
	 * Play the video.
	 * 
	 */
	public void play() {
		player.play();
	}

	/**
	 * Stop the video.
	 * 
	 */
	public void stop() {
		player.stop();

	}

	/**
	 * Pause the video.
	 */
	public void pause() {
		player.pause();

	}

	/**
	 * Load the next video in the playlist and play.
	 */
	public void next() {
		player.setInputPlaybinFile(playlist.next());
	}

	/**
	 * Load the previous video in the playlist and play.
	 */
	public void preview() {
		player.setInputPlaybinFile(playlist.preview());
	}

	/**
	 * Test if the video is playing
	 * 
	 * @return true if the video if playing, false otherwise.
	 */
	public boolean isPlaying() throws Exception {
		return player.isPlaying();
	}

	/**
	 * Add a list of file to the current playlist. If the file don't exist, he
	 * will be not add, this operation occurs in a silent mode.
	 * 
	 * @param files
	 *            The list with the path of the video files.
	 * @throws Exception
	 *             if the files is Empty or null.
	 */
	public void addPlayList(List<String> files) throws Exception {
		playlist.addPlayList(files);
	}

	/**
	 * Set the current play list position to Zero.
	 */
	public void positionToZero() {
		playlist.positionToZero();
	}

	/**
	 * Replaces the current list with a new list.
	 * 
	 * @param files
	 *            The new list.
	 * @throws Exception
	 *             If the argument is null or empty.
	 */
	public void setPlayList(List<String> files) throws Exception {
		playlist.setPlayList(files);
	}

	/**
	 * Clear the current playlist.
	 */
	public void clearPlayList() {
		playlist.clearPlayList();
	}

	/**
	 * Add a video to thelist
	 * 
	 * @param file
	 *            A video file to add.
	 */
	public void addVideo(File file) throws Exception {
		playlist.addVideo(file);
	}

	/**
	 * Provides the current list.
	 * 
	 * @return The current list.
	 */
	public List<File> getPlayList() {
		return playlist.getPlayList();
	}

	/**
	 * Remove a file from the list.
	 * 
	 * @param file
	 *            the file to remove.
	 */
	public void remove(File file) {
		playlist.remove(file);

	}

	/**
	 * remove all the files in the list.
	 * 
	 */
	public void removeAll() {
		playlist.removeAll();

	}

	/**
	 * Return the current position in the playlist.
	 * 
	 * @return The actual position.
	 */
	public int curretPosition() {
		return playlist.curretPosition();
	}

	/**
	 * Return the file that is current playing, or loaded to play.
	 * 
	 * @return The current video file.
	 */
	public File currentVideo() {
		return playlist.currentVideo();

	}

	/**
	 * play the video in a new position. (The position must be between 0 and the
	 * size of the playlist.
	 * 
	 * @param newPosition
	 *            the position to play.
	 * @throws Exception
	 *             If the position is out of bounds.
	 */
	public void toPosition(int newPosition) throws Exception {
		playlist.toPosition(newPosition);
		player.setInputPlaybinFile(currentVideo());
	}

	/**
	 * The action at the end of the actual video. This is called in the end of
	 * the file, the Bus, send a messenger at the end of stream, it is called
	 * when this messenger comes.
	 */
	private void endOfVideoEvent() {
		endOfVideo = new Bus.EOS() {

			@Override
			public void endOfStream(GstObject arg0) {
				next();
			}
		};
	}

	/**
	 * Set the news that provides the feeds.
	 * 
	 * @param news
	 *            An instance of News.
	 */
	public void setNews(News news) {
		player.setNews(news);
	}

	/**
	 * Provides some features to the video player. Space(play/pause), f(to next
	 * video), r(the previous video), s(stop).
	 */
	private void upadateKeyListeners() {
		KeyListener keyListener = new KeyListener() {
			@Override
			public void keyPressed(KeyEvent keyEvent) {

				if (keyEvent.getKeyCode() == KeyEvent.VK_SPACE) {
					try {
						if (player.isPlaying()) {
							pause();
						} else {
							play();
						}
					} catch (Exception e) {

					}
				}

				if (keyEvent.getKeyCode() == KeyEvent.VK_F) {
					next();
				}

				if (keyEvent.getKeyCode() == KeyEvent.VK_R) {
					preview();
				}

				if (keyEvent.getKeyCode() == KeyEvent.VK_S) {
					try {
						stop();
					} catch (Exception e) {

					}
				}
			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}
		};

		player.getRunVideo().addKeyListener(keyListener);
	}
}
